using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Baula.TextGen.ActiveTemplating
{
    public interface IDefaultContextMapping
    {
        IEnumerable<string> WellKnownPlaceholders { get; }
        string GetCodeForWellKnownPlaceholder(string wellKnownPlaceholder);
    }

    public class DefaultContextMapping : IDefaultContextMapping
    {
        private readonly Dictionary<string, Expression<Func<DefaultContext, string>>> _mappings;

        public DefaultContextMapping()
        {
            _mappings = new Dictionary<string, Expression<Func<DefaultContext, string>>>
                        {
                            {"AUTHOR", (DefaultContext dc) => dc.Author},
                            {"DATE", (DefaultContext dc) => dc.CurrentDateAsString},
                            {"TIME", (DefaultContext dc) => dc.CurrentTimeAsString},
                            {"MODULE_NAME", (DefaultContext dc) => dc.ModuleName},
                            {"MODULE_TYPE", (DefaultContext dc) => dc.ModuleTypeAsString},
                            {"PROCEDURE_NAME", (DefaultContext dc) => dc.ProcedureName},
                            {"FUNCTION_RETURN_TYPE_NAME", (DefaultContext dc) => dc.ReturnType},
                            {"FUNCTION_RETURN_TYPE_PREFIX", (DefaultContext dc) => dc.ReturnTypePrefix},
                            {"PROCEDURE_TYPE", (DefaultContext dc) => dc.ProcedureTypeAsString},
                            {"PROJECT_NAME", (DefaultContext dc) => dc.ProjectName}
                        };
        }

        private string GetMemberName<T, U>(Expression<Func<T, U>> expression)
        { 
            var member = expression.Body as MemberExpression; 
            if (member != null)         
                return member.Member.Name; 
            throw new ArgumentException("Expression is not a member access", "expression"); 
        } 

        public virtual IEnumerable<string> WellKnownPlaceholders
        {
            get { return _mappings.Keys; }
        }

        public virtual string GetCodeForWellKnownPlaceholder(string wellKnownPlaceholder)
        {
            if (!_mappings.ContainsKey(wellKnownPlaceholder))
                throw new ArgumentOutOfRangeException("wellKnownPlaceholder");

            return "Context.DefaultContext." + GetMemberName(_mappings[wellKnownPlaceholder]);
        }
    }
}